#include<iostream>
#include<memory>
#include<mutex>
#include<thread>

class Single1
{
    private:

        static Single1 *single1_; //要求先初始化
        Single1() = default;//私有构造，禁止外部构造
        Single1(const Single1 &si) = delete;
        Single1& operator=(Single1 &si) = delete;
        
    public:
        static Single1* getInstance()
        {
            if (single1_ == nullptr)
            {
                single1_ = new Single1;
                return single1_;
            }
            return single1_;
        };
    
        void PrintAdderss(){std::cout << "single1's address:" << single1_ << std::endl;};
};

//Single1* Single1::single1_ = nullptr;//初始化为空,懒汉式::这种做法要使用加锁的方式，实行双检锁方式防止并发线程重复初始化single1:详情见./Singleton Pattern.cpp
//这种方式存在一个很严重的问题，就是当多个线程都调用单例函数时，我们不确定资源是被哪个线程初始化的。
//回收指针存在问题，存在多重释放或者不知道哪个指针释放的问题。可以使用智能指针规避这个问题

//使用智能指针之后需要防止开发人员使用delete删除指针这个问题

//为了规避用户手动释放内存，可以提供一个辅助类帮忙回收内存
//并将单例类的析构函数写为私有
class SingleAutoSafe;
class SafeDeletor
{
public:
    void operator()(SingleAutoSafe* sf)
    {
        std::cout << "this is safe deleter operator()" << std::endl;
        delete sf;
    }
};
class SingleAutoSafe
{
private:
    SingleAutoSafe() {}
    ~SingleAutoSafe()
    {
        std::cout << "this is single auto safe deletor" << std::endl;
    }
    SingleAutoSafe(const SingleAutoSafe&) = delete;
    SingleAutoSafe& operator=(const SingleAutoSafe&) = delete;
    //定义友元类，通过友元类调用该类析构函数
    friend class SafeDeletor;
public:
    static std::shared_ptr<SingleAutoSafe> GetInst()
    {
        //1处
        if (single != nullptr)
        {
            return single;
        }
        s_mutex.lock();
        //2处
        if (single != nullptr)
        {
            s_mutex.unlock();
            return single;
        }
        //额外指定删除器  
        //3 处
        single = std::shared_ptr<SingleAutoSafe>(new SingleAutoSafe, SafeDeletor());
        //也可以指定删除函数
        // single = std::shared_ptr<SingleAutoSafe>(new SingleAutoSafe, SafeDelFunc);
        s_mutex.unlock();
        return single;
    }
private:
    static std::shared_ptr<SingleAutoSafe> single;
    static std::mutex s_mutex;
};

/*
但是上面的代码存在危险，比如懒汉式的使用方式，当多个线程调用单例时，有一个线程加锁进入3处的逻辑。
其他的线程有的在1处，判断指针非空则跳过初始化直接使用单例的内存会存在问题。
主要原因在于SingleAutoSafe * temp = new SingleAutoSafe() 这个操作是由三部分组成的
1 调用allocate开辟内存
2 调用construct执行SingleAutoSafe的构造函数
3 调用赋值操作将地址赋值给temp

而现实中2和3的步骤可能颠倒，所以有可能在一些编译器中通过优化是1，3，2的调用顺序，
其他线程取到的指针就是非空，还没来的及调用构造函数就交给外部使用造成不可预知错误。
为解决这个问题，C++11 推出了std::call_once函数保证多个线程只执行一次
*/

class SingletonOnce {
private:
    SingletonOnce() = default;
    SingletonOnce(const SingletonOnce&) = delete;
    SingletonOnce& operator = (const SingletonOnce& st) = delete;
    static std::shared_ptr<SingletonOnce> _instance;
public :
    static std::shared_ptr<SingletonOnce> GetInstance() {
        static std::once_flag s_flag;
        std::call_once(s_flag, [&]() {
            _instance = std::shared_ptr<SingletonOnce>(new SingletonOnce);
            });
        return _instance;
    }
    void PrintAddress() {
        std::cout << _instance.get() << std::endl;
    }
    ~SingletonOnce() {
        std::cout << "this is singleton destruct" << std::endl;
    }
};
std::shared_ptr<SingletonOnce> SingletonOnce::_instance = nullptr;


Single1* Single1::single1_ = Single1::getInstance();//使用前先初始化,饿汉式
//饿汉式是从使用角度规避多线程的安全问题，很多情况下我们很难从规则角度限制开发人员，所以这种方式不是很推荐。

//************************************************
//这种写法在c++11以后能保证线程安全
class Single2 {
private:
    Single2()
    {
    }
    Single2(const Single2&) = delete;
    Single2& operator=(const Single2&) = delete;
public:
    static Single2& GetInst()
    {
        static Single2 single;
        return single;
    }
};

//*****************************************************

//为了使用单例类更通用，比如项目中使用多个单例类，可以通过继承实现多个单例类

//为了让单例更加通用，可以做成模板类
template <typename T>
class Singleton {
protected:
    Singleton() = default;
    Singleton(const Singleton<T>&) = delete;
    Singleton& operator=(const Singleton<T>& st) = delete;
    static std::shared_ptr<T> _instance;
public:
    static std::shared_ptr<T> GetInstance() {
        static std::once_flag s_flag;
        std::call_once(s_flag, [&]() {
            _instance = std::shared_ptr<T>(new T);
            });
        return _instance;
    }
    void PrintAddress() {
        std::cout << _instance.get() << std::endl;
    }
    ~Singleton() {
        std::cout << "this is singleton destruct" << std::endl;
    }
};
template <typename T>
std::shared_ptr<T> Singleton<T>::_instance = nullptr;
//比如我们想实现单例类，就像我们之前在网络编程中介绍的那样，可以通过继承实现单例模式

//想使用单例类，可以继承上面的模板，我们在网络编程中逻辑单例类用的就是这种方式
class LogicSystem :public Singleton<LogicSystem>
{
    friend class Singleton<LogicSystem>;
public:
    ~LogicSystem(){}
private:
    LogicSystem(){}
};

/*
如果你只是实现一个简单的单例类推荐使用返回局部静态变量的方式
如果想大规模实现多个单例类可以用call_once实现的模板类。
*/


int main(int argc, char const *argv[])
{
    Single1* single = Single1::getInstance();
    single->PrintAdderss();
    Single1* single1 = Single1::getInstance();
    single1->PrintAdderss();
    Single1* single2 = Single1::getInstance();
    single2->PrintAdderss();
    Single1* single3 = Single1::getInstance();
    single3->PrintAdderss();
    Single1* single4 = Single1::getInstance();
    single4->PrintAdderss();
    return 0;
}
